/***********************************************************************************
 * 文件名： PortDev.h
 * 作者： 刘言
 * 版本： 1
 * 说明：
 *      以物理端口区分的设备类：端口设备。针对PTC端口和TC端口，目的是合并这2个端口上的设备操作
 *  函数。目前支持1个PTC设备：雾化器设备，2个TC设备：电池设备、一体雾化设备。
 *      本文件使用面向对象的思想设计，C++的Class将属性（变量）和函数封装在一起，C语言使用
 *  struct可以一定程度上替代Class。虽然struct也可以利用函数指针变量的方式将函数封装在struct内
 *  部，但是实例化对象时总需要重复的给这些函数指针赋值，会增加一些代码量，而且函数指针本身也会
 *  增加RAM使用量。本文件面向对象的实现方案是：在struct内只封装属性，通过调用统一的函数来操作不
 *  同的对象。损失了一定的封装性，但是节省了一定的资源，规避了 KEIL C51 编译器可能的函数指针功能
 *  不完善引起的问题。
 *      使用之前需要先实例化（定义）一个PortDev对象,然后对其进行初始化（设置基础属性）。调用函
 *  数来操作对象时必须将对象地址传递给函数（第一个参数）。
 * 		本文件提供的接口函数见文件末尾。
 * 		使用流程: 初始化后，定时调用 PortDev_Detect 检测设备是否接入，如果设备接入了，预设的
 *  回调函数将会被调用，之后可以使用 PortDev_Read PortDev_Write 来操作设备。其它函数可以在任意
 *  时刻调用。
 * 修改记录：
 * 	2020/6/15: 初版。 刘言。
***********************************************************************************/
#ifndef _PORTDEV_H_
#define _PORTDEV_H_

#include "TDevCom.h"

// 参数定义

#define PORTDEV_DEVICE_TYPE_ADDR    0XFF    // 设备类型标志的地址
#define PORTDEV_RAND_NUM_ADDR       0XEC    // TC设备通信随机数的地址

#define ATOM_HAVE_DATA_ADDR		0X78	// 判断雾化器是否有数据的地址
#define BATT_HAVE_DATA_ADDR		0XB8	// 判断电池是否有数据的地址
#define INTE_HAVE_DATA_ADDR		0X78	// 判断一体雾化设备是否有数据的地址

#define PMS_DATA_BLOCK_NUM_MAX   2          // 单个权限对应的数据块数量的最大值

// 雾化器设备的CID（客户ID）的地址
#define ATOM_CUSTID_ADDR 	0x74	

// 雾化器权限0（工厂）数据区域数量
#define ATOM_P0_DB_NUM         2
// 雾化器权限0（工厂）数据区域开始与结束地址
#define ATOM_P0_START		{0X40 ,0X70}
#define ATOM_P0_END		    {0x5F ,0X7E}
// 雾化器权限9（用户）数据区域数量
#define ATOM_P9_DB_NUM         1
// 雾化器权限9（用户）数据区域开始与结束地址，一定要大括号
#define ATOM_P9_START		{0X60}
#define ATOM_P9_END		    {0x6F}


// 电池设备的CID（客户ID）的地址
#define BATT_CUSTID_ADDR 	0xB4

// 电池权限0（工厂）数据区域数量
#define BATT_P0_DB_NUM         1
// 电池权限0（工厂）数据区域开始与结束地址
#define BATT_P0_START		{0XB0}
#define BATT_P0_END		    {0XBF}
// 电池权限9（用户）数据区域数量
#define BATT_P9_DB_NUM         1
// 电池权限9（用户）数据区域开始与结束地址，一定要大括号
#define BATT_P9_START		{0X17}
#define BATT_P9_END		    {0xAF}


// 一体雾化设备的CID（客户ID）的地址
#define INTE_CUSTID_ADDR 	0x74	

// 一体雾化权限0（工厂）数据区域数量
#define INTE_P0_DB_NUM         1
// 一体雾化权限0（工厂）数据区域开始与结束地址
#define INTE_P0_START		{0X50}
#define INTE_P0_END		    {0x7F}
// 一体雾化权限9（用户）数据区域数量
#define INTE_P9_DB_NUM         1
// 一体雾化权限9（用户）数据区域开始与结束地址，一定要大括号
#define INTE_P9_START		{0X10}
#define INTE_P9_END		    {0x3F}


// 自定义类型

// 权限信息数据结构, 每个权限编号对应的数据的信息
typedef struct _pms_info
{
    u8 DbNum;      // 该权限数据块数量
    u16 StartAddr[PMS_DATA_BLOCK_NUM_MAX];      // 各个数据块的起始地址
    u16 EndAddr[PMS_DATA_BLOCK_NUM_MAX];        // 各个数据块的结束地址
}pms_info_t;

// 权限信息列表联合体，支持 数组方式访问 和 权限号访问 2种访问方式
typedef union _pms_info_list
{
    pms_info_t Item[2];     // 目前只需要保存2个权限信息，权限0 和 权限9。
    struct _Dir
    {
        pms_info_t P0;
        pms_info_t P9;
    }Dir;
}pms_info_list_t;

// 雾化器设备权限信息列表值
#define PORTDEV_ATOM_PMS_INFO   \
{                               \
    {                           \
        {                       \
            ATOM_P0_DB_NUM,     \
            ATOM_P0_START,      \
            ATOM_P0_END         \
        },                      \
        {                       \
            ATOM_P9_DB_NUM,     \
            ATOM_P9_START,      \
            ATOM_P9_END         \
        }                       \
    }                           \
}

// 电池设备权限信息列表值
#define PORTDEV_BATT_PMS_INFO   \
{                               \
    {                           \
        {                       \
            BATT_P0_DB_NUM,     \
            BATT_P0_START,      \
            BATT_P0_END         \
        },                      \
        {                       \
            BATT_P9_DB_NUM,     \
            BATT_P9_START,      \
            BATT_P9_END         \
        }                       \
    }                           \
}

// 一体雾化设备权限信息列表值
#define PORTDEV_INTE_PMS_INFO   \
{                               \
    {                           \
        {                       \
            INTE_P0_DB_NUM,     \
            INTE_P0_START,      \
            INTE_P0_END         \
        },                      \
        {                       \
            INTE_P9_DB_NUM,     \
            INTE_P9_START,      \
            INTE_P9_END         \
        }                       \
    }                           \
}

// 回调函数类型
typedef bool (*PortDev_callback_t)();

// 设备类型
typedef enum _device_type
{
    PORTDEV_BATTERY = 0x00,
    PORTDEV_INTEGRATED = 0x01,
    PORTDEV_ATOMIZER = 0x5A
}device_type_t;

// PortDev 类(某种端口的设备)
typedef struct _PortDev
{
    TDevCom Parent;    // 通信组件（决定了通信接口与协议，这里可看做是继承，在C语言里面继承就是定义，只是把定义放在最开始）

    const pms_info_list_t code *pPmsInfoList;  // 指向权限信息表的指针
    u8 mPermission;     // 当前权限等级，数字越小权限越高，即不可以修改更小的权限区域
    u8 mCustID;         // 客户ID
    bool mHaveData;     // 内部是否有数据标志。

}PortDev;


// APIs

void PortDev_Init(PortDev *obj, protocol_t protocol);
void PortDev_SetCallBacks(PortDev_callback_t ptc_loadcallback, 
                                    PortDev_callback_t ptc_unloadcallback,
                                    PortDev_callback_t tc_loadcallback,
                                    PortDev_callback_t tc_unloadcallback);
u8 PortDev_GetErrorCode(PortDev *obj);
bool PortDev_Write(PortDev *obj, u16 addr, u16 len, const u8 *buff);
bool PortDev_Read(PortDev *obj, u16 addr, u16 len, u8 *buff);
bool PortDev_Recognition(PortDev *obj, u8 local_cid);
void PortDev_Reload(PortDev *obj);
void PortDev_Detect(PortDev *obj);




#endif


